//============================================================================
// Name        : HeMmseg.cpp
// Author      : dd
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
#include <sstream>
#include <map>
#include <functional>
#include <sys/time.h>

#include "mmseg/Dictionary.h"
#include "mmseg/MMSeg.h"

using namespace std;
using namespace mmseg;

#define MAXLINE 10240
typedef void (*Command)(char**, int);

map<string, Command> Commands;
Dictionary* mDic;

void show(char** param, int size) {
	mDic->outWord([](string word) {
		cout << word << endl;
	});
	cout << "词语显示完成" << endl;
}

void showPos(char** param, int size) {
	showAllPost([](const char* pos, const char* text) {
		cout << "\t"<<pos<<"\t"<<text << endl;
	});
	cout << "词性显示完成" << endl;
}

void init(char** param, int size) {
	struct timeval tpstart, tpend;
	float timeuse;

	gettimeofday(&tpstart, NULL);

	if (0 == size) {
		cout << "正在重新加载默认词典..." << endl;
		mDic->init(mDic->defaultDictionary());

	} else {
		DicFile files(param[0]);
		for (int i = 1; i < size; i++) {
			files.addFile(param[i]);
		}
		cout << "正在加载词典..." << endl;
		mDic->init(&files);
	}
	gettimeofday(&tpend, NULL);
	timeuse = (1000000 * (tpend.tv_sec - tpstart.tv_sec) + tpend.tv_usec - tpstart.tv_usec) / 1000;
	cout << "词典加载完成，用时 " << timeuse << endl;
}

void add(char** param, int size) {
	mDic->addWord(param[0], (size > 1) ? stringToPos(param[1]) : un, (size > 2) ? param[2] : "");
	cout << "添加词语完成" << endl;
}

void save(char** param, int size) {
	mDic->save(NULL);
	cout << "保存词典完成" << endl;
}

void parse(char** param, int size) {
	if (size) {
		MMSeg seg(param[0], mDic);
		seg.start([&](int start, int len, EnumPos pos, string other) {
			string word(seg.c_str(),start,len);
			cout << "{";
			cout << "\"word\":\""<< word << "\",";
			cout << "\"offset\":"<< start<< ",";
			cout << "\"count\":"<< len << ",";
			cout << "\"pos\":\""<< posToString(pos) << "\",";
			cout << "\"other\":"<< (other.size()?other:"null");
			cout << "}";
			cout << endl;
		});
		cout << "分词完成" << endl;
	}
}

void showHelp(char** param, int size) {
	int sun = -1;
	if (!param || !size || !(sun = strcmp("init", param[0]))) {
		cout << "init\t-i\t初始化词典" << endl;
		if (!sun) {
			cout << "\t[init -i] [\"词典文件路径\" ...]　文件路径尽量使用双引号括起来，多个文件路径用空格分开，空路径将重新加载默认词典．" << endl;
			cout << "\t[init -i] 重新加载默认词典．" << endl;
		}
	}

	sun = -1;
	if (!param || !size || !(sun = strcmp("show", param[0]))) {
		cout << "show\t-s\t显示所有词语" << endl;
	}

	sun = -1;
	if (!param || !size || !(sun = strcmp("add", param[0]))) {
		cout << "add\t-a\t添加词语" << endl;
		if (!sun) {
			cout << "\t[add -a] [词语] [词性] [其它]　如果[其它]中包含引号、空格时，请使用单引号括起来,　使用[help pos]查看所有词．" << endl;
			cout << "\t特殊符号" << endl;
			cout << "\t\t\ \\$ 	数字" << endl;
			cout << "\t\t\ \\# 	小写字母" << endl;
			cout << "\t\t\ \\& 	大小字母" << endl;
			cout << "\t\t\ \\$\\#	数字+小写字母" << endl;
			cout << "\t\t\ \\$\\&	数字+大写字母" << endl;
			cout << "\t\t\ \\#\\&	小写字母+大写字母" << endl;
			cout << "\t\t\ \\$\\#\\& 数字＋小写字母+大写字母" << endl;
			cout << "\t符号使用" << endl;
			cout << "\t\tadd \\$年\\$月\\$日 t '{\"format\":\"yyyy年MM月dd日\"}' 添加一个日期词语" << endl;
		}
	}

	sun = -1;
	if (!param || !size || !(sun = strcmp("save", param[0]))) {
		cout << "save\t-v\t保存词语到词典" << endl;
	}

	sun = -1;
	if (!param || !size || !(sun = strcmp("parse", param[0]))) {
		cout << "parse\t-p\t开始分词" << endl;
		if (!sun)
			cout << "\t[parse -p] [\"需要分词的字符串\"]" << endl;
	}

	sun = -1;
	if (!param || !size || !(sun = strcmp("parse", param[0]))) {
		cout << "pos\t-o\t显示所有词性" << endl;
	}

	sun = -1;
	if (!param || !size || !(sun = strcmp("help", param[0]))) {
		if (sun)
			cout << "exit\t  \t退出程序" << endl;

		cout << "help\t-h\t显示帮助信息" << endl;
		cout << "\t[help -h] [子命令] 显示命令详情" << endl;
	}
}

UTF_8 getChar(const char* str) {
	UTF_8 key = 0;

	int size = 1;
	char temp = *str;
	if (temp & 0x80) {
		temp <<= 1;
		do {
			temp <<= 1;
			++size;
		} while (temp & 0x80);
	}

	memcpy(&key, str, size);
	UTF_SIZE(key) = size;

	return key;
}

void removeSpace(char** str, char* end) {
	while (*str < end && **str && **str == ' ') {
		(*str)++;
	};
}

void getWord(char** str, char* endAdd, char end) {
	UTF_8 key;
	do {
		key = getChar(*str);
		(*str) += UTF_SIZE(key);

	} while (*str < endAdd && **str && end != **str);
}

bool getLine(char* line) {
	char *str;
	char end = ' ';
	char* param[50];
	int i = 0;
	char* endAdd = line + MAXLINE;

	memset(line, MAXLINE, sizeof(char));
	cin.getline(line, MAXLINE);
	str = line;

	removeSpace(&str, endAdd);
	if (endAdd > str && *str) {
		param[i] = str;
		i++;
		while (endAdd > str && *str) {
			getWord(&str, endAdd, end);
			*str = 0;
			str++;
			removeSpace(&str, endAdd);

			if (endAdd > str && *str) {
				if ('"' == *str || '\'' == *str) {
					end = *str;
					str++;
					if (endAdd > str && *str) {
						param[i] = str;
						i++;
					}
				} else {
					param[i] = str;
					i++;
					end = ' ';
				}
			}
		};
	}

	if (i) {
		if (!strcmp("exit", param[0]))
			return false;

		Command comm = Commands[param[0]];
		if (comm)
			comm(param + 1, i - 1);
		else
			showHelp(nullptr, 0);
		return true;
	}

	return true;
}

int main() {
	struct timeval tpstart, tpend;
	float timeuse;

	Commands["show"] = show;
	Commands["init"] = init;
	Commands["add"] = add;
	Commands["save"] = save;
	Commands["parse"] = parse;
	Commands["help"] = showHelp;
	Commands["pos"] = showPos;

	Commands["-s"] = show;
	Commands["-i"] = init;
	Commands["-a"] = add;
	Commands["-v"] = save;
	Commands["-p"] = parse;
	Commands["-o"] = showPos;
	Commands["-h"] = showHelp;

	cout << "分词程序　版本 Ver1.0.0" << endl;
	cout << "\t程序采用正向最大化词匹配，词典优先算法，支持中文、英文、数字和英文数字混合分词．" << endl;
	cout << "\t使用 help 或 -h 查看所有命令" << endl << endl;

	auto dic = Dictionary::getInstance();

	cout << "正在加载默认词典..." << endl;
	gettimeofday(&tpstart, NULL);
	mDic = &dic;
	dic.init(dic.defaultDictionary());

	gettimeofday(&tpend, NULL);
	timeuse = (1000000 * (tpend.tv_sec - tpstart.tv_sec) + tpend.tv_usec - tpstart.tv_usec) / 1000;
	cout << "词典加载完成，用时 " << timeuse << endl;

	char* line = (char*) malloc(MAXLINE);
	while (getLine(line))
		;
	cout << "已退出" << endl;
	return 0;
}
